import json
import re
from django.conf import settings
from django_redis import get_redis_connection
from rest_framework.permissions import BasePermission
import logging

from BYD_ERP.utils.cache_permissions import redis_storage_permissions

logger = logging.getLogger('erp')

class RbacPermission(BasePermission):

    def do_uri(self, url):
        """
        把一个不完整的接口地址，变成一个完整的。 /users/----->/api/users/
        """
        base_api = settings.BASE_API
        uri = '/' + base_api + '/' + url + '/'
        # sub()：实现去重
        # 在正则表达式中“+”代表一个或者多个
        # 针对uri，将一个或者多个“/”替换成一个“/”
        return re.sub('/+', '/', uri)

    def has_permission(self, request, view):
        # has_permission：代指“是否有权限”
        # has_permission：此函数返回值为bool类型，在此函数内，如果返回True就代表有权限
        """
        判断是否有权限，该函数必须要重写
        思路和步骤：
        1.获取请求的URL，和请求方法method，user用户对象
        2.判断是否白名单的url，或者用户的角色是admin（最高权限的用户）也直接放行
        3.从redis中得到当前登录用户的所有权限
        4.判断是否存在权限
        """
        # 获得请求路由
        request_url = request.path
        request_method = request.method
        logger.info(f'请求地址为：{request_url}，请求方法为：{request_method}')
        for safe_url in settings.WHITE_LIST:
            if re.match(settings.REGEX_URL.format(url=safe_url), request_url):
                # 如果匹配成功了就是白名单
                # has_permission：此函数返回值为bool类型，在此函数内，如果返回True就代表有权限
                return True
        # 获取当前登录用户
        user = request.user
        # 获取用户的所有角色
        role_name_list = user.roles.values_list('name', flat=True)
        if 'admin' in role_name_list:
            return True

        # 从redis中来获取该用户的所有权限
        redis_conn = get_redis_connection('default')
        if not redis_conn.exists(f'user_{user.id}'):
            # 如果redis中没有缓存权限，重新做下缓存，同时也为了以后用起来更方便。
            redis_storage_permissions(user)

        # 得到所有的权限中key，其中key是接口的url地址
        # hkeys：获得所有的key
        url_keys = redis_conn.hkeys(f'user_{user.id}')
        redis_key = None
        for url_key in url_keys:
            # 注意：redis中存放的是字节数据。
            if re.match(settings.REGEX_URL.format(url=self.do_uri(url_key.decode())), request_url):
                # 如果redis中的url和请求url是一致的
                redis_key = url_key.decode()
                # break表示终止循环，就是说key找到了
                break

        if redis_key:
            # 这时下面的permission是字典
            permissions = json.loads(redis_conn.hget(f'user_{user.id}', redis_key).decode())
            for permission in permissions:
                if permission.get('method') == request_method:
                    return True
        else:
            return False
        pass